package cn.yuan.user.service.impl;

import cn.yuan.basic.Exception.BusinessException;
import cn.yuan.basic.constant.UserConstants;
import cn.yuan.basic.service.impl.BaseServiceImpl;
import cn.yuan.basic.util.HttpClientUtils;
import cn.yuan.basic.util.MD5Utils;
import cn.yuan.basic.util.StrUtils;
import cn.yuan.user.domain.Logininfo;
import cn.yuan.user.domain.User;
import cn.yuan.user.domain.WxUser;
import cn.yuan.user.dto.LoginDto;
import cn.yuan.user.mapper.LogininfoMapper;
import cn.yuan.user.mapper.UserMapper;
import cn.yuan.user.mapper.WxUserMapper;
import cn.yuan.user.service.ILoginService;
import cn.yuan.util.AjaxResult.AjaxResult;
import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import sun.misc.UCDecoder;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.prefs.BackingStoreException;
@Service
public class LoginServiceImpl implements ILoginService {
    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private LogininfoMapper logininfoMapper;

    @Autowired
    private WxUserMapper wxUserMapper;
    @Autowired
    private UserMapper userMapper;

    @Override
    public Map<String, Object> accountLogin(LoginDto loginDto) {
        //1.校验
        // 1.1 空校验
        if(StringUtils.isEmpty(loginDto.getUsername())
                || StringUtils.isEmpty(loginDto.getPassword())
                ||StringUtils.isEmpty(loginDto.getType())
        ){
            throw new BusinessException("请输入完整的信息");
        }
        // 1.2 查询用户是否存在
        Logininfo info = logininfoMapper.loadByUser(loginDto);
        //如果不存在 报错
        if(info==null){
            throw new BusinessException("用户不存在！");
        }
        // 1.2.1 如果存在。校验密码
        String salt = info.getSalt();
        String md5 = MD5Utils.encrypByMd5(loginDto.getPassword() + salt);
        if(!md5.equals(info.getPassword())){
            throw new BusinessException("账号或密码错误！！");
        }
        // 1.2.2 禁用校验
        if(info.getDisable()!=1){
            throw new BusinessException("账号已经被冻结，请联系客服！");
        }
        //2 登录成功
        // 2.1 生成token（UUID.randomUUID()生成一个随机数）
        String token = UUID.randomUUID().toString();
        // 2.2 存redis
        redisTemplate.opsForValue().set(token, info, 30, TimeUnit.MINUTES);
        //3 返回 token loginInfo信息
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        //4.作为高级技师的我们，应该前端用不到的敏感信息屏蔽掉
        info.setSalt(null);
        info.setPassword(null);
        map.put("logininfo", info);
        return map;
//        if(StringUtils.isEmpty(loginDto.getUsername())
//                ||StringUtils.isEmpty(loginDto.getPassword())
//                ||StringUtils.isEmpty(loginDto.getType())){
//            throw new BusinessException("请输入完整信息");
//        }
//        Logininfo info = logininfoMapper.loadByUser(loginDto);
//        if(info==null){
//            throw new BusinessException("用户不存在");
//        }
//        String salt = info.getSalt();
//        String md5Pwd = MD5Utils.encrypByMd5(loginDto.getPassword()+salt);
//        if(!md5Pwd.equals(info.getPassword())){
//            throw new BusinessException("账号或密码错误");
//        }
//        if(info.getDisable()!=1){
//            throw new BusinessException("账号已经被冻结，请联系客服！");
//        }
//        String token = UUID.randomUUID().toString();
//        redisTemplate.opsForValue().set(token, info, 30 ,TimeUnit.MINUTES);
//        Map<String,Object> map = new HashMap<>();
//        map.put("token", token);
//        info.setPassword(null);
//        info.setSalt(null);
//        map.put("logininfo", info);
//        return map;

    }


    @Override
    public AjaxResult wechatLogin(String code) {
        //1.通过code拿token OAuth中第二步
        String getTokenUrl = UserConstants.GET_TOKEN_URL
                .replace("APPID", UserConstants.APPID)
                .replace("SECRET", UserConstants.SECRET)
                .replace("CODE", code);
        String tokenStr = HttpClientUtils.httpGet(getTokenUrl);
        if(StringUtils.isEmpty(tokenStr)){
            throw  new BusinessException("获取token失败！！");
        }
        //2.获取到token，已经自带了openid（微信号）
        JSONObject tokenObj = JSONObject.parseObject(tokenStr);
        String accessToken = tokenObj.getString("access_token");
        String openId = tokenObj.getString("openid");

        //3.查询t_wxuser ，看有有没有微信用户
        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
        if(wxUser!=null && wxUser.getUser_id()!=null){//直接免密登录
            //3.1 如果有 + 绑定userId ：直接免密登录
            //登录成功
            Logininfo info = logininfoMapper.loadByUserId(wxUser.getUser_id());
            // 3.1.1  生成token
            String token = UUID.randomUUID().toString();
            // 3.1.2 存redis
            redisTemplate.opsForValue().set(token, info, 30, TimeUnit.MINUTES);
            //3.1.3 返回 token loginInfo信息
            HashMap<Object, Object> map = new HashMap<>();
            map.put("token", token);
            //3.1.4.作为高级技师的我们，应该前端用不到的敏感信息屏蔽掉
            info.setSalt(null);
            info.setPassword(null);
            map.put("logininfo", info);
            return AjaxResult.me().setResultObj(map);
        }else {
            //3.2 如果没有 封装token + openid 返回前端，让它跳转到绑定页面
            String resultUrlParam = "accessToken=" +accessToken+"&openId="+openId;
            return AjaxResult.me().setSuccess(false).setResultObj(resultUrlParam);
        }
//        String getTokenUrl = UserConstants.GET_TOKEN_URL
//                .replace("APPID", UserConstants.APPID)
//                .replace("SECRET", UserConstants.SECRET)
//                .replace("CODE", code);
//        String tokenStr = HttpClientUtils.httpGet(getTokenUrl);
//        if(StringUtils.isEmpty(tokenStr)){
//            throw new BusinessException("获取token失败");
//        }
//        JSONObject tokenObj = JSONObject.parseObject(tokenStr);
//        String accessToken = tokenObj.getString("access_token");
//        String openId = tokenObj.getString("openid");
//        WxUser wxUser = wxUserMapper.loadByOpenId(openId);
//        if(wxUser!=null&&wxUser.getUser_id()!=null){
//            Logininfo info = logininfoMapper.loadByUserId(wxUser.getUser_id());
//            String token = UUID.randomUUID().toString();
//            redisTemplate.opsForValue().set(token, info, 30, TimeUnit.MINUTES);
//            Map<String,Object> map = new HashMap<>();
//            map.put("token",token );
//            info.setSalt(null);
//            info.setPassword(null);
//            map.put("logininfo",info );
//            return AjaxResult.me().setResultObj(map);
//
//        }else {
//            String resultUrlParam = "accessToken="+accessToken+"&openId="+openId;
//            return AjaxResult.me().setResultObj(resultUrlParam);
//        }
    }

    @Override
    public Map<String, Object> wechatBinder(Map<String, String> param) {
        String accessToken = param.get("accessToken");
        String openId = param.get("openId");
        String phone = param.get("phone");
        String verifyCode = param.get("verifyCode");
        // 1)验证用户输入的信息有没有问题
        if(StringUtils.isEmpty(phone)
                || StringUtils.isEmpty(verifyCode)
                || StringUtils.isEmpty(accessToken)
                || StringUtils.isEmpty(openId))
        {
            throw new BusinessException("请输入完整信息！");
        }
        //A 空校验
        //B 验证码是否过期
        Object codeObj = redisTemplate.opsForValue().get(UserConstants.BINDER_CODE_PREFIX + phone);
        //2 验证码校验  不要区分大小写
        if(codeObj==null){
            throw new BusinessException("验证码已失效，请重新获取！");
        }
        String codeStr= (String) codeObj;
        String code = codeStr.split(":")[0];
        if(!code.equalsIgnoreCase(verifyCode)){
            throw new BusinessException("验证码输入错误！");
        }
        //2)查询用户有没有注册过
        User user = userMapper.loadByPhone(phone);
        //如果没有注册过：
        Logininfo info = null;
        if(user == null){
            //生成t_user
            user = initUserByPhone(phone);
            info = user2LoginInfo(user);
            logininfoMapper.save(info);
            user.setLogininfo_id(info.getId());
            userMapper.save(user);
        }else {
            // 如果注册过了
            // 把登录信息查询出来
            info = logininfoMapper.loadById(user.getLogininfo_id());

        }
        // 3)通过token等信息，到微信查询微信用户信息
        String getUserUrl = UserConstants.GET_WXUSER_URL
                .replace("ACCESS_TOKEN", accessToken)
                .replace("OPENID", openId);
        String wxUserStr = HttpClientUtils.httpGet(getUserUrl);
        //生成微信用户并绑定平台用户
        // 4) 绑定微信用户和平台用户
        WxUser wxUser = user2WxUser(wxUserStr, user);

        wxUserMapper.save(wxUser);
        // 生成t_wxUser
        // 5) 免密登录成功
        String token = UUID.randomUUID().toString();
        // 存redis
        redisTemplate.opsForValue().set(token, info, 30, TimeUnit.MINUTES);
        //返回 token loginInfo信息
        HashMap<String, Object> map = new HashMap<>();
        map.put("token", token);
        map.put("logininfo", info);

        return map;
    }


    private User initUserByPhone(String phone) {
        User user = new User();
        user.setUsername(phone);
        user.setPhone(phone);
        //生成随机32位的salt
        String salt = StrUtils.getComplexRandomString(32);
        String md5pwd = MD5Utils.encrypByMd5(StrUtils.getComplexRandomString(6) + salt);
        user.setSalt(salt);
        user.setPassword(md5pwd);
        return user;
    }

    private WxUser user2WxUser(String wxUserStr, User user) {
        //装换微信用户信息
        JSONObject jsonObject = JSONObject.parseObject(wxUserStr);
        WxUser wxUser = new WxUser();
        wxUser.setAddress(null);
        wxUser.setHeadimgurl(jsonObject.getString("headimgurl"));
        wxUser.setUser_id(user.getId());
        wxUser.setNickname(jsonObject.getString("nickname"));
        wxUser.setOpenid(jsonObject.getString("openid"));
        wxUser.setUnionid(jsonObject.getString("unionid"));
        wxUser.setSex(jsonObject.getInteger("sex"));
        return wxUser;
    }

    private Logininfo user2LoginInfo(User user) {
        Logininfo info = new Logininfo();
        BeanUtils.copyProperties(user, info);
        info.setType(1);
        return info;
    }
}
